package com.xyy.saas.payment.common.pool;

import com.xyy.saas.payment.trace.AlarmService;
import com.xyy.saas.payment.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.net.URL;
import java.util.concurrent.*;

/**
 * @author liujf
 */
@Slf4j
public class PoolUtil {

    /**
     * io密集型线程池
     */
    public static final ThreadPoolExecutor IO_POLL = new ThreadPoolExecutor(16, 32, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(50), new ThreadPoolExecutor.AbortPolicy());

    /**
     * 直接丢弃任务，但是有告警
     */
    public static final ThreadPoolExecutor ALARM_POOL = new ThreadPoolExecutor(4, 16, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), new AlarmRejectHandler(SpringUtils.getBean(AlarmService.class)));

    public static <T> Future<T> submitIoTask(Callable<T> task) {
        return IO_POLL.submit(task);
    }

    public static <T> T sneakyGet(CompletableFuture<T> future) {
        try {
            return future.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static URL sneakyUrl(String path) {
        try {
            return new URL(path);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public static class AlarmRejectHandler implements RejectedExecutionHandler {
        private AlarmService alarmService;

        public AlarmRejectHandler(AlarmService alarmService) {
            this.alarmService = alarmService;
        }

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            String msg = null;
            if (r instanceof FutureTask) {
                try {
                    Field field = FutureTask.class.getDeclaredField("callable");
                    field.setAccessible(true);
                    Object object = field.get(r);
                    if (object instanceof NamedTask) {
                        msg = object.toString();
                    }
                } catch (Exception ignore) {
                }
            }
            if (msg == null) {
                msg = r.toString();
            }
            log.info("AlarmRejectHandler coreSize:{},maxSize:{},queueSize:{} task:{}", executor.getCorePoolSize(), executor.getMaximumPoolSize(), executor.getQueue().size(), msg);
            alarmService.asyncAlarm("线程池丢弃任务策略告警", "rejectedExecution", msg, null);
        }
    }

}
